/*
 * MIT License
 *
 * Copyright (c) 2020 wen.gu <454727014@qq.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

/***************************************************************************
 * Name: service_skeleton.cpp
 *
 * Purpose: service skeleton base class implementation
 *
 * Developer:
 *   wen.gu , 2020-05-25
 *
 * TODO:
 *
 ***************************************************************************/

/******************************************************************************
 **    INCLUDES
 ******************************************************************************/
#include "ara/com/skeleton/service_skeleton.h"

#include "ara/core/map.h"
#include "ara/com/runtime/network_binding.h"

namespace ara
{
namespace com
{
namespace skeleton
{
/******************************************************************************
 **    MACROS
 ******************************************************************************/

/******************************************************************************
 **    TYPE DEFINITIONS
 ******************************************************************************/
class ServiceSkeleton::impl
{
public:
    using NetworkBindingSkeletonPtr = ara::com::runtime::NetworkBinding::NetworkBindingSkeletonPtr;
    using BindingMapper = ara::core::Map<ara::core::String, NetworkBindingSkeletonPtr>;

public:
    BindingMapper mBindings;
    BindingTypeArray mBindingTypes;
    InstanceIdentifier mInstId;
    MethodCallProcessingMode mMethodCallMode;
};
/******************************************************************************
 **  inner  CLASSES/FUNCTIONS DEFINITIONS
 ******************************************************************************/

ServiceSkeleton::ConstructionToken::ConstructionToken(ara::com::InstanceIdentifierContainer instanceIDs, MethodCallProcessingMode mode)
    :mInstIds(instanceIDs),
    mMode(mode)
{
    /** todo something */
}

ServiceSkeleton::ConstructionToken::ConstructionToken(ConstructionToken&& other)
{
    mInstIds = std::move(other.mInstIds);
    mMode = other.mMode;
}

ServiceSkeleton::ConstructionToken& ServiceSkeleton::ConstructionToken::operator=(ConstructionToken&& other)
{
    mInstIds = std::move(other.mInstIds);
    mMode = other.mMode;
    return *this;
}

/******************************************************************************
 **    CLASSES/FUNCTIONS DEFINITIONS
 ******************************************************************************/


    /**
     *@param InstanceIdentifier: The identifier of a specific instance of a service, needed
     *       to distinguish different instances of exactly the same service in the system
     *
     *@param MethodCallProcessingMode: As a default argument, this is the mode of
     *       the service implementation for processing service method invocations with
     *       kEvent as default value
     */
ServiceSkeleton::ServiceSkeleton(InstanceIdentifier instanceID, MethodCallProcessingMode mode /*= MethodCallProcessingMode::kEvent*/)
    :mImpl(new impl)
{
    /** todo something */
}


    /**
     *@param InstanceSpecifier: The specifiers of a specific instance of a service, needed
     *       to distinguish different instances of exactly the same service in the system
     *
     *@param MethodCallProcessingMode: As a default argument, this is the mode of
     *       the service implementation for processing service method invocations with
     *       kEvent as default value
     */
ServiceSkeleton::ServiceSkeleton(InstanceSpecifier instanceSpec, MethodCallProcessingMode mode /*= MethodCallProcessingMode::kEvent*/)
{
    InstanceIdentifierContainer iic = ara::com::runtime::ResolveInstanceIDs(instanceSpec);


}


    /**
     *@param InstanceIdentifierContainer: The container of instances of a service,
     *       each instance element needed to distinguish different instances of exactly the
     *       same service in the system
     *
     *@param MethodCallProcessingMode: As a default argument, this is the mode of
     *       the service implementation for processing service method invocations with
     *       kEvent as default value
     */
ServiceSkeleton::ServiceSkeleton(ara::com::InstanceIdentifierContainer instanceIDs, MethodCallProcessingMode mode /*= MethodCallProcessingMode::kEvent*/)
{

}

ServiceSkeleton::ServiceSkeleton(ConstructionToken&& other) noexcept
{

}

ServiceSkeleton::ServiceSkeleton(ServiceSkeleton&& other) noexcept
{

}


ServiceSkeleton::~ServiceSkeleton()
{

}

ServiceSkeleton& ServiceSkeleton::operator=(ServiceSkeleton&& other)
{

}


    /**
     *@param InstanceIdentifier: The identifier of a specific instance of a service, needed
     *       to distinguish different instances of exactly the same service in the system
     *
     *@param MethodCallProcessingMode: As a default argument, this is the mode of
     *       the service implementation for processing service method invocations with
     *       kEvent as default value
     */
//static 
ServiceSkeleton::Result<ServiceSkeleton::ConstructionToken> ServiceSkeleton::Preconstruct(InstanceIdentifier instanceID, MethodCallProcessingMode mode /*= MethodCallProcessingMode::kEvent*/)
{

}


    /**
     *@param InstanceSpecifier: The specifiers of a specific instance of a service, needed
     *       to distinguish different instances of exactly the same service in the system
     *
     *@param MethodCallProcessingMode: As a default argument, this is the mode of
     *       the service implementation for processing service method invocations with
     *       kEvent as default value
     */
//static 
ServiceSkeleton::Result<ServiceSkeleton::ConstructionToken> ServiceSkeleton::Preconstruct(InstanceSpecifier instanceSpec, MethodCallProcessingMode /*mode = MethodCallProcessingMode::kEvent*/)
{

}

    /**
     *@param InstanceIdentifierContainer: The container of instances of a service,
     *       each instance element needed to distinguish different instances of exactly the
     *       same service in the system
     *
     *@param MethodCallProcessingMode: As a default argument, this is the mode of
     *       the service implementation for processing service method invocations with
     *       kEvent as default value
     */
//static 
ServiceSkeleton::Result<ServiceSkeleton::ConstructionToken> ServiceSkeleton::Preconstruct(ara::com::InstanceIdentifierContainer instanceIDs, MethodCallProcessingMode mode = MethodCallProcessingMode::kEvent)
{

}


void ServiceSkeleton::OfferService()
{

}

void ServiceSkeleton::StopOfferService()
{

}


/**only for MethodCallProcessingMode::kPoll, otherwise throw exception */
ara::core::Future<bool> ServiceSkeleton::ProcessNextMethodCall()
{

}

/**todo, refine me, only used by cm implementation, not for user */
/**todo define some special functon to implementation method call */

ServiceSkeleton::DeserializerPtr ServiceSkeleton::GetDeserializer(const NetworkBindingType& type, uint8_t* data, uint32_t size)
{
    impl::BindingMapper::iterator it = mImpl->mBindings.find(type);

    if (it != mImpl->mBindings.end())
    {
        impl::NetworkBindingSkeletonPtr nbsp = it->second;
        if (nbsp)
        {
            return nbsp->GetDeserializer(data, size);
        }
    }

    return nullptr;
}

ServiceSkeleton::SerializerPtr ServiceSkeleton::GetSerializer(const NetworkBindingType& type)
{
    impl::BindingMapper::iterator it = mImpl->mBindings.find(type);

    if (it != mImpl->mBindings.end())
    {
        impl::NetworkBindingSkeletonPtr nbsp = it->second;
        if (nbsp)
        {
            return nbsp->GetSerializer();
        }
    }

    return nullptr;
}

ServiceSkeleton::MessagePtr ServiceSkeleton::MakeMessage(const NetworkBindingType& bindType, MessageType type)
{
    impl::BindingMapper::iterator it = mImpl->mBindings.find(bindType);

    if (it != mImpl->mBindings.end())
    {
        impl::NetworkBindingSkeletonPtr nbsp = it->second;
        if (nbsp)
        {
            return nbsp->MakeMessage(type);
        }
    }

    return nullptr;
}

void ServiceSkeleton::RegisterReceiveHandler(const ara::core::String& name, MessageType mt, SkeletonReceiveHandler handler)
{

}

bool ServiceSkeleton::SendResponse(MessagePtr msg)
{

}

bool ServiceSkeleton::SendError(MessagePtr msg, ComErrc err)
{

}

bool ServiceSkeleton::SendEvent(MessagePtr msg)
{

}

bool ServiceSkeleton::SendFeildAck(MessagePtr msg)
{

}

const ServiceSkeleton::BindingTypeArray& ServiceSkeleton::GetBindingTypes(void)
{
    return mImpl->mBindingTypes;
}

} /** namespace skeleton */
} /** namespace com */
} /** namespace ara */